{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lesson-01 Assignment"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 今天是2020年08月16日，今天世界上又多了一名AI工程师 :) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 本次作业的内容"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 1. 复现课堂代码\n",
    "\n",
    "在本部分，你需要参照我们给大家的GitHub地址里边的课堂代码，结合课堂内容，复现内容。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 1.1 基于规则的语言模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 172,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def adj():  return random.choice('蓝色的 | 好看的 | 小小的'.split('|')).split()[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def adj_star():\n",
    "    return random.choice([lambda : '', lambda : adj() + adj_star()])()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'蓝色的小小的小小的好看的'"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "adj_star()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 根据语法描述生成语法规则"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "adj_grammar = \"\"\"\n",
    "Adj* => null | Adj Adj*\n",
    "Adj =>  蓝色的 | 好看的 | 小小的\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 根据语法描述 grammar_str 生成规则 grammar\n",
    "def create_grammar(grammar_str, split='=>', line_split='\\n'):\n",
    "    grammar = {}\n",
    "    for line in grammar_str.split(line_split):\n",
    "        if not line.strip(): continue\n",
    "        exp, stmt = line.split(split)\n",
    "        grammar[exp.strip()] = [s.split() for s in stmt.split('|')]\n",
    "    return grammar"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "# # 根据语法描述 adj_grammar 生成语法规则 grammar\n",
    "grammar = create_grammar(adj_grammar)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'Adj*': [['null'], ['Adj', 'Adj*']], 'Adj': [['蓝色的'], ['好看的'], ['小小的']]}"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grammar"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[['null'], ['Adj', 'Adj*']]"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grammar['Adj*']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[['蓝色的'], ['好看的'], ['小小的']]"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grammar['Adj']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 根据语法规则生成句子"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 根据语法规则生成句子\n",
    "choice = random.choice\n",
    "\n",
    "def generate(gram, target):\n",
    "    if target not in gram: return target # means target is a terminal expression #1\n",
    "    \n",
    "    expaned = [generate(gram, t) for t in choice(gram[target])]  #2\n",
    "    return ''.join([e if e != '/n' else '\\n' for e in expaned if e != 'null']) #3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 语法描述\n",
    "simple_grammar = \"\"\"\n",
    "sentence => noun_phrase verb_phrase\n",
    "noun_phrase => Article Adj* noun\n",
    "Adj* => null | Adj Adj*                  \n",
    "verb_phrase => verb noun_phrase\n",
    "Article =>  一个 | 这个\n",
    "noun =>   女人 |  篮球 | 桌子 | 小猫\n",
    "verb => 看着   |  坐在 |  听着 | 看见\n",
    "Adj =>  蓝色的 | 好看的 | 小小的\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 根据语法描述生成语法规则\n",
    "example_grammar = create_grammar(simple_grammar)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'sentence': [['noun_phrase', 'verb_phrase']],\n",
       " 'noun_phrase': [['Article', 'Adj*', 'noun']],\n",
       " 'Adj*': [['null'], ['Adj', 'Adj*']],\n",
       " 'verb_phrase': [['verb', 'noun_phrase']],\n",
       " 'Article': [['一个'], ['这个']],\n",
       " 'noun': [['女人'], ['篮球'], ['桌子'], ['小猫']],\n",
       " 'verb': [['看着'], ['坐在'], ['听着'], ['看见']],\n",
       " 'Adj': [['蓝色的'], ['好看的'], ['小小的']]}"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 生成的语法规则\n",
    "example_grammar"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'这个蓝色的好看的小小的好看的小猫看见这个小小的篮球'"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 根据语法规则生成句子\n",
    "generate(gram=example_grammar, target='sentence')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "先生,您好我是67445456号,您需要喝酒吗？\n",
      "我找找乐子\n",
      "先生,你好我是4号,请问你要喝酒吗？\n",
      "我们想找点乐子\n",
      "您好我是84号,您需要赌博吗？\n",
      "俺想找点玩的\n",
      "您好我是6号,请问你要喝酒吗？\n",
      "我找找玩的\n",
      "女士,您好我是4号,您需要打牌吗？\n",
      "我找找乐子\n",
      "女士,您好我是7749号,请问你要喝酒吗？\n",
      "俺想找点乐子\n",
      "您好我是7号,请问你要打牌吗？\n",
      "我想找点乐子\n",
      "女士,你好我是64号,请问你要打牌吗？\n",
      "俺想找点乐子\n",
      "您好我是5号,您需要喝酒吗？\n",
      "我找找玩的\n",
      "你好我是5473号,请问你要喝酒吗？\n",
      "我想找点乐子\n",
      "小朋友,您好我是8号,您需要打牌吗？\n",
      "我想找点玩的\n",
      "女士,你好我是2号,您需要打猎吗？\n",
      "俺找找玩的\n",
      "你好我是63号,您需要喝酒吗？\n",
      "俺找找乐子\n",
      "小朋友,你好我是53号,您需要打猎吗？\n",
      "我们找找玩的\n",
      "您好我是39号,您需要打牌吗？\n",
      "俺找找乐子\n",
      "您好我是53号,您需要打猎吗？\n",
      "我们想找点玩的\n",
      "您好我是6号,您需要赌博吗？\n",
      "俺想找点玩的\n",
      "小朋友,你好我是6号,您需要打猎吗？\n",
      "俺想找点玩的\n",
      "女士,你好我是214号,请问你要赌博吗？\n",
      "我们想找点玩的\n",
      "你好我是94号,请问你要赌博吗？\n",
      "我找找乐子\n"
     ]
    }
   ],
   "source": [
    "# 例子2\n",
    "#在西部世界里，一个”人类“的语言可以定义为：\n",
    "\n",
    "human = \"\"\"\n",
    "human = 自己 寻找 活动\n",
    "自己 = 我 | 俺 | 我们 \n",
    "寻找 = 找找 | 想找点 \n",
    "活动 = 乐子 | 玩的\n",
    "\"\"\"\n",
    "\n",
    "\n",
    "#一个“接待员”的语言可以定义为\n",
    "\n",
    "host = \"\"\"\n",
    "host = 寒暄 报数 询问 业务相关 结尾 \n",
    "报数 = 我是 数字 号 ,\n",
    "数字 = 单个数字 | 数字 单个数字 \n",
    "单个数字 = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 \n",
    "寒暄 = 称谓 打招呼 | 打招呼\n",
    "称谓 = 人称 ,\n",
    "人称 = 先生 | 女士 | 小朋友\n",
    "打招呼 = 你好 | 您好 \n",
    "询问 = 请问你要 | 您需要\n",
    "业务相关 = 玩玩 具体业务\n",
    "玩玩 = null\n",
    "具体业务 = 喝酒 | 打牌 | 打猎 | 赌博\n",
    "结尾 = 吗？\n",
    "\"\"\"\n",
    "for i in range(20):\n",
    "    print(generate(gram=create_grammar(host, split='='), target='host'))\n",
    "    print(generate(gram=create_grammar(human, split='='), target='human'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 输入的语法描述改变，程序不变"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "if(info_8>=info_name){/Nif(databasestudent){/Nif(lib_database<database_database_lib_lib_database_2){/Nif(database_1_7==info){/Nif(student_info_name_7>=lib_7_0){/Ndatabase_1_7=lib_lib_name_info_lib_info_student/N}/N}else{/Nif(database_5_1<=lib_database_database_0_9){/Ndatabase_2_7_0=lib/N}/N}/N}else{/Nif(student_4_8_1_5_8<student_7_6){/Nif(database_lib_4database){/Nif(info==info_lib_1_9){/Ndatabase_name_student=info_database_3/N}else{/Nlib_database_student=info/N}/N}/N}/N}/N}/N}else{/Nstudent_lib_1_2=database/N}\n"
     ]
    }
   ],
   "source": [
    "# 例子3：\n",
    "simpel_programming = '''\n",
    "programming => if_stmt | assign | while_loop\n",
    "while_loop => while ( cond ) { change_line stmt change_line }\n",
    "if_stmt => if ( cond )  { change_line stmt change_line } | if ( cond )  { change_line stmt change_line } else { change_line stmt change_line } \n",
    "change_line => /N\n",
    "cond => var op var\n",
    "op => | == | < | >= | <= \n",
    "stmt => assign | if_stmt\n",
    "assign => var = var\n",
    "var =>  var _ num | words \n",
    "words => words _ word | word \n",
    "word => name | info |  student | lib | database \n",
    "nums => nums num | num\n",
    "num => 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0\n",
    "'''\n",
    "# 根据语法规则生成一段代码\n",
    "print(generate(gram=create_grammar(simpel_programming, split='=>'), target='programming'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 例子4：格式化输出\n",
    "def pretty_print(line):\n",
    "    # utility tool function\n",
    "    lines = line.split('/N')\n",
    "    \n",
    "    code_lines = []\n",
    "    \n",
    "    for i, sen in enumerate(lines):\n",
    "        if i < len(lines) / 2: \n",
    "            #print()\n",
    "            code_lines.append(i * \"  \" + sen)\n",
    "        else:\n",
    "            code_lines.append((len(lines) - i) * \" \" + sen)\n",
    "    \n",
    "    return code_lines"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "generated_programming = []\n",
    "# 根据语法描述生成20段代码\n",
    "for i in range(20):\n",
    "    generated_programming += pretty_print(generate(gram=create_grammar(simpel_programming, split='=>'), target='programming'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "student=database\n",
      "if(name==student_database_5){\n",
      "  if(database_9>=lib_name_9_5_5_4){\n",
      "    name=name_student\n",
      "      }\n",
      "        }else{\n",
      "          if(student_database_database_student_0_8info_1_0_3){\n",
      "     student_name_8=student_3\n",
      "    }else{\n",
      "   name=name_info_6_7\n",
      "  }\n",
      " }\n",
      "name=name_9\n",
      "while(lib_2<info_4_4){\n",
      "  name_student_info=student\n",
      " }\n",
      "if(name<=lib_info_5){\n",
      "  if(liblib_8_8){\n",
      "    if(student_2_5<student_info){\n",
      "      if(name<lib_lib_info_database_3){\n",
      "        info_9_5=student_8_4\n",
      "          }\n",
      "            }else{\n",
      "              if(database>=student_lib_name_5){\n",
      "                if(database<info_7_3){\n",
      "                  if(studentlib_student_0){\n",
      "                    student_info_name_database_info_name_name_5_8=lib_4_1_3_6\n",
      "                      }\n",
      "                        }else{\n",
      "                          lib=info_9_9\n",
      "                            }\n",
      "                              }else{\n",
      "                                if(lib<=info_name){\n",
      "                                  lib_database_info_info=database_student_2_6_0\n",
      "                 }else{\n",
      "                info=student_student_info_info_lib\n",
      "               }\n",
      "              }\n",
      "             }\n",
      "            }else{\n",
      "           if(lib_student_lib_3student_database_name_info){\n",
      "          if(lib>=lib_name){\n",
      "         if(name_info_8_4_7>=lib){\n",
      "        info_6=database_2\n",
      "       }\n",
      "      }\n",
      "     }\n",
      "    }\n",
      "   }else{\n",
      "  database_lib_database=name_lib_lib_student_1_2_5_3_5_7\n",
      " }\n",
      "while(lib_student_6_3_8student){\n",
      "  if(name_student>=lib_info_info){\n",
      "    name=lib_lib_lib_student_lib_4_8_3_2\n",
      "  }\n",
      " }\n",
      "while(lib_info_1_5<info_student_9){\n",
      "  if(database_lib_database>=database){\n",
      "    if(lib_2_4==info_6_5){\n",
      "      if(name_libdatabase){\n",
      "        if(database>=lib){\n",
      "          name_1_5=student_lib_info_lib_3_2_2_6_1_3_3_2_6\n",
      "            }\n",
      "              }\n",
      "                }else{\n",
      "                  database=database_3_0_9\n",
      "                    }\n",
      "                      }else{\n",
      "                        if(database_name_name<lib_6){\n",
      "                          if(name_lib_database<name_database_name_info_database_lib_info_student_7_4_0_7_4_2){\n",
      "                            if(database_name_database_student_name_student_info_9>=info_database_9){\n",
      "                              if(lib>=student_1){\n",
      "                                if(name_info>=database_info_name_student_4){\n",
      "                                  if(name_student_database_name==lib){\n",
      "                                    database_student_0_2=lib_2\n",
      "                                      }else{\n",
      "                                        if(student<database_lib){\n",
      "                                          name_6=name_student_4_6_9_0\n",
      "                                            }\n",
      "                      }\n",
      "                     }else{\n",
      "                    if(student>=info_7_0_4_0){\n",
      "                   lib_9_1_2_9=lib_info_name\n",
      "                  }\n",
      "                 }\n",
      "                }\n",
      "               }else{\n",
      "              if(info_3_9_2_4_9>=student){\n",
      "             info_info_lib_student_student_8_0_3=info_student\n",
      "            }\n",
      "           }\n",
      "          }else{\n",
      "         if(name_student_student_lib<=database){\n",
      "        name=name\n",
      "       }\n",
      "      }\n",
      "     }else{\n",
      "    lib=name\n",
      "   }\n",
      "  }\n",
      " }\n",
      "while(info_info_lib_info==student_4_2_1_5_5_2){\n",
      "  if(info_database_database_database_8<info_0){\n",
      "    info=lib_student\n",
      "  }\n",
      " }\n",
      "while(student_5>=lib_info){\n",
      "  lib_name_database_student_lib=lib\n",
      " }\n",
      "while(student_name_info<lib_student_5_1_3_5){\n",
      "  info_name_name=database\n",
      " }\n",
      "while(lib_student_lib_student_infoname){\n",
      "  if(lib>=lib){\n",
      "    if(lib_student_lib_student_namestudent_database_9){\n",
      "      database_lib_name=lib_5_5_5\n",
      "        }\n",
      "    }else{\n",
      "   student_info_database_info_5_6=database_5\n",
      "  }\n",
      " }\n",
      "name_9=lib\n",
      "if(student_name_libdatabase_info){\n",
      "  lib=info_name_1\n",
      " }\n",
      "student_database_student_database_name_name_lib_database_6_6_3_4=student_student_0\n",
      "while(info_8_9<=lib_database_database){\n",
      "  if(lib_database_student_info_name_9_2_6_3_3<=database_lib_5){\n",
      "    student_lib=database_0_4\n",
      "      }else{\n",
      "   name_9_1_0=lib_name_info_7_5\n",
      "  }\n",
      " }\n",
      "while(database_database<=student_4_7_0_8){\n",
      "  database_lib_name=name\n",
      " }\n",
      "while(student_student_student_namestudent_5){\n",
      "  if(database_database_8_4_2_0_7_2<info_database_name_1){\n",
      "    if(database==student_info_name_9){\n",
      "      if(info_namestudent_info){\n",
      "        if(name_info_name_1_3==lib){\n",
      "          lib_database_4_3_4_1_6_3=info_0_6\n",
      "            }\n",
      "              }\n",
      "                }else{\n",
      "                  if(name>=student_2){\n",
      "                    if(lib_9_0_6==info){\n",
      "                      database_student_name=lib_8_8\n",
      "           }else{\n",
      "          lib_lib=lib_name_0\n",
      "         }\n",
      "        }else{\n",
      "       lib_lib_name_5_8_7=name_database_lib\n",
      "      }\n",
      "     }\n",
      "    }else{\n",
      "   database=name_info_database\n",
      "  }\n",
      " }\n",
      "info_lib=info_6\n",
      "if(student_database_info_5student_database){\n",
      "  info_lib=name_database\n",
      "    }else{\n",
      "  lib_student=database_database\n",
      " }\n",
      "if(lib_info>=lib_8){\n",
      "  database_3_6=database\n",
      " }\n"
     ]
    }
   ],
   "source": [
    "# 打印20段代码\n",
    "for line in generated_programming:\n",
    "    print(line)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 1.2 Language Model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$$ language\\_model(String) = Probability(String) \\in (0, 1) $$\n",
    "$$ Pro(w_1 w_2 w_3 w_4) = Pr(w_1 | w_2 w_3 w_ 4) * P(w2 | w_3 w_4) * Pr(w_3 | w_4) * Pr(w_4)$$ \n",
    "$$ Pro(w_1 w_2 w_3 w_4) \\sim Pr(w_1 | w_2 ) * P(w2 | w_3 ) * Pr(w_3 | w_4) * Pr(w_4)$$ \n",
    "how to get $ Pr(w1 | w2 w3 w4) $ ?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random\n",
    "import jieba"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [],
   "source": [
    "import re\n",
    "from collections import Counter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [],
   "source": [
    "from functools import reduce\n",
    "from operator import add, mul\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 数据预处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 读取文件\n",
    "filename = 'sqlResult_1558435.csv'\n",
    "content = pd.read_csv(filename, encoding='gb18030')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>id</th>\n",
       "      <th>author</th>\n",
       "      <th>source</th>\n",
       "      <th>content</th>\n",
       "      <th>feature</th>\n",
       "      <th>title</th>\n",
       "      <th>url</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>89617</td>\n",
       "      <td>NaN</td>\n",
       "      <td>快科技@http://www.kkj.cn/</td>\n",
       "      <td>此外，自本周（6月12日）起，除小米手机6等15款机型外，其余机型已暂停更新发布（含开发版/...</td>\n",
       "      <td>{\"type\":\"科技\",\"site\":\"cnbeta\",\"commentNum\":\"37\"...</td>\n",
       "      <td>小米MIUI 9首批机型曝光：共计15款</td>\n",
       "      <td>http://www.cnbeta.com/articles/tech/623597.htm</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>89616</td>\n",
       "      <td>NaN</td>\n",
       "      <td>快科技@http://www.kkj.cn/</td>\n",
       "      <td>骁龙835作为唯一通过Windows 10桌面平台认证的ARM处理器，高通强调，不会因为只考...</td>\n",
       "      <td>{\"type\":\"科技\",\"site\":\"cnbeta\",\"commentNum\":\"15\"...</td>\n",
       "      <td>骁龙835在Windows 10上的性能表现有望改善</td>\n",
       "      <td>http://www.cnbeta.com/articles/tech/623599.htm</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>89615</td>\n",
       "      <td>NaN</td>\n",
       "      <td>快科技@http://www.kkj.cn/</td>\n",
       "      <td>此前的一加3T搭载的是3400mAh电池，DashCharge快充规格为5V/4A。\\r\\n...</td>\n",
       "      <td>{\"type\":\"科技\",\"site\":\"cnbeta\",\"commentNum\":\"18\"...</td>\n",
       "      <td>一加手机5细节曝光：3300mAh、充半小时用1天</td>\n",
       "      <td>http://www.cnbeta.com/articles/tech/623601.htm</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>89614</td>\n",
       "      <td>NaN</td>\n",
       "      <td>新华社</td>\n",
       "      <td>这是6月18日在葡萄牙中部大佩德罗冈地区拍摄的被森林大火烧毁的汽车。新华社记者张立云摄\\r\\n</td>\n",
       "      <td>{\"type\":\"国际新闻\",\"site\":\"环球\",\"commentNum\":\"0\",\"j...</td>\n",
       "      <td>葡森林火灾造成至少62人死亡 政府宣布进入紧急状态（组图）</td>\n",
       "      <td>http://world.huanqiu.com/hot/2017-06/10866126....</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>89613</td>\n",
       "      <td>胡淑丽_MN7479</td>\n",
       "      <td>深圳大件事</td>\n",
       "      <td>（原标题：44岁女子跑深圳约会网友被拒，暴雨中裸身奔走……）\\r\\n@深圳交警微博称：昨日清...</td>\n",
       "      <td>{\"type\":\"新闻\",\"site\":\"网易热门\",\"commentNum\":\"978\",...</td>\n",
       "      <td>44岁女子约网友被拒暴雨中裸奔 交警为其披衣相随</td>\n",
       "      <td>http://news.163.com/17/0618/00/CN617P3Q0001875...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      id      author                  source  \\\n",
       "0  89617         NaN  快科技@http://www.kkj.cn/   \n",
       "1  89616         NaN  快科技@http://www.kkj.cn/   \n",
       "2  89615         NaN  快科技@http://www.kkj.cn/   \n",
       "3  89614         NaN                     新华社   \n",
       "4  89613  胡淑丽_MN7479                   深圳大件事   \n",
       "\n",
       "                                             content  \\\n",
       "0  此外，自本周（6月12日）起，除小米手机6等15款机型外，其余机型已暂停更新发布（含开发版/...   \n",
       "1  骁龙835作为唯一通过Windows 10桌面平台认证的ARM处理器，高通强调，不会因为只考...   \n",
       "2  此前的一加3T搭载的是3400mAh电池，DashCharge快充规格为5V/4A。\\r\\n...   \n",
       "3    这是6月18日在葡萄牙中部大佩德罗冈地区拍摄的被森林大火烧毁的汽车。新华社记者张立云摄\\r\\n   \n",
       "4  （原标题：44岁女子跑深圳约会网友被拒，暴雨中裸身奔走……）\\r\\n@深圳交警微博称：昨日清...   \n",
       "\n",
       "                                             feature  \\\n",
       "0  {\"type\":\"科技\",\"site\":\"cnbeta\",\"commentNum\":\"37\"...   \n",
       "1  {\"type\":\"科技\",\"site\":\"cnbeta\",\"commentNum\":\"15\"...   \n",
       "2  {\"type\":\"科技\",\"site\":\"cnbeta\",\"commentNum\":\"18\"...   \n",
       "3  {\"type\":\"国际新闻\",\"site\":\"环球\",\"commentNum\":\"0\",\"j...   \n",
       "4  {\"type\":\"新闻\",\"site\":\"网易热门\",\"commentNum\":\"978\",...   \n",
       "\n",
       "                           title  \\\n",
       "0           小米MIUI 9首批机型曝光：共计15款   \n",
       "1     骁龙835在Windows 10上的性能表现有望改善   \n",
       "2      一加手机5细节曝光：3300mAh、充半小时用1天   \n",
       "3  葡森林火灾造成至少62人死亡 政府宣布进入紧急状态（组图）   \n",
       "4       44岁女子约网友被拒暴雨中裸奔 交警为其披衣相随   \n",
       "\n",
       "                                                 url  \n",
       "0     http://www.cnbeta.com/articles/tech/623597.htm  \n",
       "1     http://www.cnbeta.com/articles/tech/623599.htm  \n",
       "2     http://www.cnbeta.com/articles/tech/623601.htm  \n",
       "3  http://world.huanqiu.com/hot/2017-06/10866126....  \n",
       "4  http://news.163.com/17/0618/00/CN617P3Q0001875...  "
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "content.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "89611\n"
     ]
    }
   ],
   "source": [
    "# 提取 content 列\n",
    "articles = content['content'].tolist()\n",
    "print(len(articles))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 正则查找所有字词\n",
    "def token(string):\n",
    "    # we will learn the regular expression next course.\n",
    "    return re.findall('\\w+', string)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Building prefix dict from the default dictionary ...\n",
      "Dumping model to file cache C:\\Users\\sunsh\\AppData\\Local\\Temp\\jieba.cache\n",
      "Loading model cost 1.149 seconds.\n",
      "Prefix dict has been built succesfully.\n"
     ]
    }
   ],
   "source": [
    "# 将第110条语句进行分词并计数\n",
    "with_jieba_cut = Counter(jieba.cut(articles[110]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[('，', 88),\n",
       " ('的', 73),\n",
       " ('。', 39),\n",
       " ('\\r\\n', 27),\n",
       " ('了', 20),\n",
       " ('们', 18),\n",
       " ('工作队', 16),\n",
       " ('村民', 15),\n",
       " ('收割', 14),\n",
       " ('、', 12)]"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 词频最高的10个词\n",
    "with_jieba_cut.most_common()[:10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'在外国名著麦田里的守望者中作者想要守护麦田里如自己内心一般纯真的孩子们而驻村干部们也在这个炎热的夏天里撸袖子上阵真正做起了村民们的麦田守望者三夏时节不等人你看到了吗不停翻涌起伏仿若铺陈至天边的金黄麦浪中那若隐若现的人影是自治区新闻出版广电局驻和田市肖尔巴格乡合尼村工作队的队员与工作队组织的青年志愿者在这个炎热的夏季他们深入田间地头帮助村民们收割小麦扛起收麦机麦田中的每个人都显得兴致勃勃一天下来就近22亩小麦收割完毕志愿者麦麦提亚森擦去满脸的汗水高兴地告诉驻村队员我们青年志愿者应该多做贡献为村里的脱贫致富出把力工作队带着我们为村里的老人服务看到那些像我爷爷奶奶一样的老人赞许感谢的目光我体会到了帮助他人的快乐自治区新闻出版广电局驻村工作队孙敏艾力依布拉音麦收时节我们在一起6月中旬的和田墨玉麦田金黄静待收割6月14日15日两天自治区高级人民法院驻和田地区墨玉县吐外特乡罕勒克艾日克村工作队与48名村民志愿者一道帮助村里29户有需要的村民进行小麦收割工作田间地头罕勒克艾日克村志愿队的红旗迎风飘扬格外醒目10余台割麦机一起轰鸣男人们在用机器收割小麦的同时几名妇女也加入到志愿队构成了一道美丽的麦收风景休息空闲工作队员和村民们坐在树荫下田埂上互相问好聊天语言交流有困难就用手势动作比划着聊天有趣地交流方式不时引来阵阵欢笑大家在一同享受丰收和喜悦也一同增进着彼此的情感和友谊自治区高级人民法院驻村工作队周春梅艾地艾木阿不拉细看稻菽千重浪6月15日自治区煤田灭火工程局的干部职工们再一次跋涉1000多公里来到了叶城县萨依巴格乡阿亚格欧尔达贝格村见到了自己的亲戚现场处处都透出掩盖不住的喜悦一声声亲切的谢谢一个个结实的拥抱都透露出浓浓的亲情没坐一会儿在嘘寒问暖中大家了解到在麦收的关键时刻部分村民家中却存在收割难的问题小麦成熟期短收获的时间集中天气的变化对小麦最终产量的影响极大如果不能及时收割会有不小损失的于是大家几乎立刻就决定要帮助亲戚们收割麦子在茂密的麦地里干部们每人手持一把镰刀一字排开挽起衣袖卷起裤腿挥舞着镰刀进行着无声的竞赛骄阳似火汗如雨下但这都挡不住大家的热情随着此起彼伏的镰刀割倒麦子的刷刷声响不一会一束束沉甸甸的麦穗就被整齐地堆放了起来当看到自己亲手收割的金黄色麦穗被一簇簇地打成捆运送到晒场每个人的脸上都露出了灿烂的笑容自治区煤田灭火工程局驻村工作队马浩南这是一个收获多多的季节6月13日清晨6时许和田地区民丰县若雅乡特开墩村的麦田里已经传来马达轰鸣声原来是自治区质监局驻村工作队趁着天气尚且凉爽开始了麦田的收割工作忙碌间隙志愿者队伍搬来清凉的水村民们拎来鲜甜的西瓜抹一把汗水吃一牙西瓜甜蜜的汁水似乎流进了每一个人的心里说起割麦子对于生活在这片土地上的村民来说是再平常不过的事但是对于工作队队员们来说却是陌生的自治区质监局驻民丰县若克雅乡博斯坦村工作队队员们一开始觉得十几个人一起收割二亩地应该会挺快的结果却一点不简单镰刀拿到自己手里割起来考验才真正的开始大家弓着腰弯着腿亦步亦趋手上挥舞着镰刀时刻注意不要让镰刀割到自己脚下还要留心不要把套种的玉米苗踩伤不一会儿就已经汗流浃背了抬头看看身边的村民早就远远地割到前面去了只有今年已经56岁的工作队队长李树刚有割麦经验多少给队员们挽回了些面子赶不上村民们割麦子的速度更不要说搞定收割机这台大家伙了现代化的机械收割能成倍提升小麦的收割速度李树刚说不过能有这样的体验拉近和村民的距离也是很难得的体验自治区质监局驻村工作队王辉马君刚我们是麦田的守护者为了应对麦收新疆银监局驻和田县塔瓦库勒乡也先巴扎村工作队一早就从经济支援和人力支援两方面做好了准备一方面工作队帮村里购入了5台小麦收割机另一边还组织村干部青年团员等组成了6支近百人的收割先锋突击队帮助村民们抢收麦子看着及时归仓的麦子村民们喜得合不拢嘴纷纷摘下自家杏树上的杏子送给工作队金黄的麦穗温暖了村民们的心香甜的杏子温暖了工作队员的心麦子加杏子拉近了村民和队员们的心新疆银监局驻村工作队王继发免责声明本文仅代表作者个人观点与环球网无关其原创性以及文中陈述文字和内容未经本站证实对本文以及其中全部或者部分内容文字的真实性完整性及时性本站不作任何保证或承诺请读者仅作参考并请自行核实相关内容'"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 查找第110条记录的所有字词，无空格连接\n",
    "''.join(token(articles[110]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "89611\n"
     ]
    }
   ],
   "source": [
    "# 查找每条记录的所有字词，无空格连接\n",
    "articles_clean = [''.join(token(str(a)))for a in articles]\n",
    "print(len(articles_clean))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 保存到文件\n",
    "with open('article_9k.txt', 'w') as f:\n",
    "    for a in articles_clean:\n",
    "        f.write(a + '\\n')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 分词"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义分词函数\n",
    "def cut(string): return list(jieba.cut(string))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "100\n",
      "200\n",
      "300\n",
      "400\n",
      "500\n",
      "600\n",
      "700\n",
      "800\n",
      "900\n",
      "1000\n",
      "1100\n",
      "1200\n",
      "1300\n",
      "1400\n",
      "1500\n",
      "1600\n",
      "1700\n",
      "1800\n",
      "1900\n",
      "2000\n",
      "2100\n",
      "2200\n",
      "2300\n",
      "2400\n",
      "2500\n",
      "2600\n",
      "2700\n",
      "2800\n",
      "2900\n",
      "3000\n",
      "3100\n",
      "3200\n",
      "3300\n",
      "3400\n",
      "3500\n",
      "3600\n",
      "3700\n",
      "3800\n",
      "3900\n",
      "4000\n",
      "4100\n",
      "4200\n",
      "4300\n",
      "4400\n",
      "4500\n",
      "4600\n",
      "4700\n",
      "4800\n",
      "4900\n",
      "5000\n",
      "5100\n",
      "5200\n",
      "5300\n",
      "5400\n",
      "5500\n",
      "5600\n",
      "5700\n",
      "5800\n",
      "5900\n",
      "6000\n",
      "6100\n",
      "6200\n",
      "6300\n",
      "6400\n",
      "6500\n",
      "6600\n",
      "6700\n",
      "6800\n",
      "6900\n",
      "7000\n",
      "7100\n",
      "7200\n",
      "7300\n",
      "7400\n",
      "7500\n",
      "7600\n",
      "7700\n",
      "7800\n",
      "7900\n",
      "8000\n",
      "8100\n",
      "8200\n",
      "8300\n",
      "8400\n",
      "8500\n",
      "8600\n",
      "8700\n",
      "8800\n",
      "8900\n",
      "9000\n",
      "9100\n",
      "9200\n",
      "9300\n",
      "9400\n",
      "9500\n",
      "9600\n",
      "9700\n",
      "9800\n",
      "9900\n",
      "10000\n"
     ]
    }
   ],
   "source": [
    "# 将保存到文件中的前10000行字词进行分词\n",
    "TOKEN = []\n",
    "\n",
    "for i, line in enumerate((open('article_9k.txt'))):\n",
    "    if i % 100 == 0: print(i)\n",
    "    \n",
    "    # replace 10000 with a big number when you do your homework. \n",
    "    \n",
    "    if i > 10000: break    \n",
    "    TOKEN += cut(line)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "23"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# reduce 加操作\n",
    "reduce(add, [1, 2, 3, 4, 5, 8])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 3, 3, 43, 5]"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 列表加操作\n",
    "[1, 2, 3] + [3, 43, 5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[('的', 184244),\n",
       " ('在', 47370),\n",
       " ('了', 36722),\n",
       " ('和', 30809),\n",
       " ('是', 30283),\n",
       " ('月', 18711),\n",
       " ('也', 15995),\n",
       " ('年', 15971),\n",
       " ('有', 14714),\n",
       " ('为', 14448),\n",
       " ('等', 14340),\n",
       " ('将', 14060),\n",
       " ('对', 13074),\n",
       " ('与', 12568),\n",
       " ('日', 12322),\n",
       " ('中', 11117),\n",
       " ('中国', 11036),\n",
       " ('6', 10477),\n",
       " ('上', 10192),\n",
       " ('不', 10027),\n",
       " ('\\n', 10001),\n",
       " ('他', 9530),\n",
       " ('都', 9447),\n",
       " ('发展', 8795),\n",
       " ('企业', 8584),\n",
       " ('就', 8537),\n",
       " ('到', 8338),\n",
       " ('市场', 8095),\n",
       " ('但', 7729),\n",
       " ('这', 7658),\n",
       " ('被', 7575),\n",
       " ('从', 7513),\n",
       " ('并', 7412),\n",
       " ('人', 7339),\n",
       " ('后', 7084),\n",
       " ('公司', 6915),\n",
       " ('一个', 6772),\n",
       " ('说', 6703),\n",
       " ('新', 6467),\n",
       " ('表示', 6309),\n",
       " ('要', 6276),\n",
       " ('还', 6245),\n",
       " ('会', 6179),\n",
       " ('个', 6176),\n",
       " ('我', 6141),\n",
       " ('而', 6090),\n",
       " ('进行', 5802),\n",
       " ('我们', 5742),\n",
       " ('记者', 5734),\n",
       " ('以', 5615),\n",
       " ('5', 5569),\n",
       " ('工作', 5135),\n",
       " ('没有', 5000),\n",
       " ('美国', 4840),\n",
       " ('下', 4741),\n",
       " ('更', 4739),\n",
       " ('通过', 4720),\n",
       " ('大', 4704),\n",
       " ('让', 4701),\n",
       " ('可以', 4681),\n",
       " ('经济', 4670),\n",
       " ('时', 4654),\n",
       " ('目前', 4645),\n",
       " ('国家', 4628),\n",
       " ('项目', 4538),\n",
       " ('问题', 4422),\n",
       " ('创新', 4416),\n",
       " ('多', 4410),\n",
       " ('已经', 4391),\n",
       " ('建设', 4373),\n",
       " ('其', 4224),\n",
       " ('自己', 4119),\n",
       " ('投资', 4064),\n",
       " ('已', 4026),\n",
       " ('3', 4008),\n",
       " ('城市', 3921),\n",
       " ('服务', 3842),\n",
       " ('报道', 3818),\n",
       " ('亿元', 3813),\n",
       " ('及', 3812),\n",
       " ('1', 3793),\n",
       " ('成为', 3684),\n",
       " ('相关', 3646),\n",
       " ('向', 3603),\n",
       " ('可能', 3595),\n",
       " ('他们', 3560),\n",
       " ('以及', 3475),\n",
       " ('或', 3447),\n",
       " ('今年', 3426),\n",
       " ('地', 3411),\n",
       " ('其中', 3408),\n",
       " ('于', 3371),\n",
       " ('她', 3349),\n",
       " ('能', 3343),\n",
       " ('10', 3330),\n",
       " ('着', 3327),\n",
       " ('2016', 3310),\n",
       " ('认为', 3295),\n",
       " ('20', 3282),\n",
       " ('称', 3271)]"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 对分词进行计数\n",
    "words_count = Counter(TOKEN)\n",
    "# 词频最高的前100个词\n",
    "words_count.most_common(100)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x20b5c6e6be0>]"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 高频词绘图\n",
    "\n",
    "# y坐标：前100个高频词的词频\n",
    "frequiences = [f for w, f in words_count.most_common(100)]\n",
    "# x坐标：100个词\n",
    "x = [i for i in range(100)]\n",
    "# 绘图\n",
    "plt.plot(x, frequiences)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x20b5c775d30>]"
      ]
     },
     "execution_count": 67,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 半指数绘图\n",
    "plt.plot(x, np.log(frequiences))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 计算概率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 计算每个词出现的概率\n",
    "def prob_1(word):\n",
    "    return words_count[word] / len(TOKEN)\n",
    "\n",
    "# count(wk)/(number of words)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.001554473157589251"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prob_1('我们')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "条件概率：p(w1|w2) = count(w1,w2)/count（w1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['此外', '自', '本周', '6', '月', '12', '日起', '除', '小米', '手机']"
      ]
     },
     "execution_count": 73,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 转为？（已经是）字符串\n",
    "TOKEN = [str(t) for t in TOKEN]\n",
    "TOKEN[:10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['此外自', '自本周', '本周6', '6月', '月12', '12日起', '日起除', '除小米', '小米手机', '手机6']"
      ]
     },
     "execution_count": 74,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 连接相邻的两个词\n",
    "TOKEN_2_GRAM = [''.join(TOKEN[i:i+2]) for i in range(len(TOKEN[:-2]))]\n",
    "TOKEN_2_GRAM[:10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 相邻连词计数\n",
    "words_count_2 = Counter(TOKEN_2_GRAM)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 计算条件概率\n",
    "def prob_2(word1, word2):  # p(w1,w2) = count(w1,2)/count(w1)\n",
    "    if word1 + word2 in words_count_2: return words_count_2[word1+word2] / words_count[word1]\n",
    "    else: # 不存在的概率设为非零值\n",
    "        return 1 / len(TOKEN_2_GRAM)\n",
    "    \n",
    "#  (w1 w2), (w3,w4) (w4,w5)  2-gram\n",
    "# (w1,w3)  1/3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.030128874956461164"
      ]
     },
     "execution_count": 78,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prob_2('我们', '在')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2.1110407430863417e-05"
      ]
     },
     "execution_count": 79,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prob_2('在', '吃饭')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2.707199580708929e-07"
      ]
     },
     "execution_count": 80,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prob_2('去', '吃饭')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 语言模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 基于语言模型，计算一条语句出现的概率\n",
    "def get_probablity(sentence):\n",
    "    words = cut(sentence)\n",
    "    \n",
    "    sentence_pro = 1\n",
    "    \n",
    "    for i, word in enumerate(words[:-1]):\n",
    "        next_ = words[i+1]\n",
    "        \n",
    "        probability = prob_2(word, next_)  # p(w1|w2)\n",
    "        \n",
    "        sentence_pro *= probability  # p(s) = p(w_1)p(w2|w1)*p(w3|w2)..p(wn|wn-1) \n",
    "    \n",
    "    return sentence_pro"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6.743762360853308e-35"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "get_probablity('小明今天抽奖抽到一台苹果手机')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "7.989690983840629e-36"
      ]
     },
     "execution_count": 83,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "get_probablity('小明今天抽奖抽到一架波音飞机')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.9840875058382383e-20"
      ]
     },
     "execution_count": 84,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "get_probablity('洋葱奶昔来一杯')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "7.3289295697906e-14"
      ]
     },
     "execution_count": 85,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "get_probablity('养乐多绿来一杯')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sentence: 一个桌子听着一个小小的小小的好看的女人 with Prb: 2.1973595663913754e-35\n",
      "sentence: 这个好看的桌子坐在这个女人 with Prb: 5.548329878462416e-29\n",
      "sentence: 这个好看的篮球看着这个蓝色的小小的桌子 with Prb: 3.0030232683627296e-40\n",
      "sentence: 一个好看的好看的桌子看见这个蓝色的篮球 with Prb: 3.166717830937892e-39\n",
      "sentence: 这个桌子坐在这个女人 with Prb: 1.3010409874349103e-23\n",
      "sentence: 一个小小的桌子听着这个蓝色的小小的桌子 with Prb: 1.871578553398883e-40\n",
      "sentence: 一个篮球看着一个好看的小小的桌子 with Prb: 1.550289033413856e-39\n",
      "sentence: 这个桌子坐在一个好看的女人 with Prb: 1.6606969906972526e-31\n",
      "sentence: 这个蓝色的桌子看着一个蓝色的女人 with Prb: 1.3878952755854437e-37\n",
      "sentence: 一个篮球看见一个桌子 with Prb: 1.7888265170123457e-19\n"
     ]
    }
   ],
   "source": [
    "# 根据语法描述生成10个句子，计算出现的概率\n",
    "for sen in [generate(gram=example_grammar, target='sentence') for i in range(10)]:\n",
    "    print('sentence: {} with Prb: {}'.format(sen, get_probablity(sen)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "明天晚上请你吃大餐，我们一起吃苹果 is more possible\n",
      "---- 今天晚上请你吃大餐，我们一起吃日料 with probility 6.684624207742742e-46\n",
      "---- 明天晚上请你吃大餐，我们一起吃苹果 with probility 7.542849854956504e-46\n",
      "真是一只好看的小猫 is more possible\n",
      "---- 真事一只好看的小猫 with probility 2.1153007661637964e-26\n",
      "---- 真是一只好看的小猫 with probility 7.813612196297205e-20\n",
      "今晚我去吃火锅 is more possible\n",
      "---- 今晚我去吃火锅 with probility 5.012457937326253e-16\n",
      "---- 今晚火锅去吃我 with probility 1.563034443630964e-18\n",
      "养乐多绿来一杯 is more possible\n",
      "---- 洋葱奶昔来一杯 with probility 1.9840875058382383e-20\n",
      "---- 养乐多绿来一杯 with probility 7.3289295697906e-14\n"
     ]
    }
   ],
   "source": [
    "# 比较两个句子出现的概率大小\n",
    "need_compared = [\n",
    "    \"今天晚上请你吃大餐，我们一起吃日料 明天晚上请你吃大餐，我们一起吃苹果\",\n",
    "    \"真事一只好看的小猫 真是一只好看的小猫\",\n",
    "    \"今晚我去吃火锅 今晚火锅去吃我\",\n",
    "    \"洋葱奶昔来一杯 养乐多绿来一杯\"\n",
    "]\n",
    "\n",
    "for s in need_compared:\n",
    "    s1, s2 = s.split()\n",
    "    p1, p2 = get_probablity(s1), get_probablity(s2)\n",
    "    \n",
    "    better = s1 if p1 > p2 else s2\n",
    "    \n",
    "    print('{} is more possible'.format(better))\n",
    "    print('-'*4 + ' {} with probility {}'.format(s1, p1))\n",
    "    print('-'*4 + ' {} with probility {}'.format(s2, p2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2. 完成以下问答和编程练习"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 基础理论部分"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 0. Can you come up out 3 sceneraies which use AI methods? "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ans: {人脸识别、机器翻译、语音助手}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 1. How do we use Github; Why do we use Jupyter and Pycharm;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ans: {\n",
    "1) Github：远程代码仓库，保存不同代码版本，便于分享和协作；\n",
    "2) Jupyter：基于服务器-客户端结构的网页应用，局部代码即时运行，交互性效果最好，支持MarkDown注释和绘图展示；\n",
    "3) Pycharm：Python专用集成开发环境，安装配置简单，功能支持全面。\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2. What's the Probability Model?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ans:{\n",
    "概率模型是描述不同随机变量之间关系的数学模型，通常情况下刻画了一个或多个随机变量之间的相互非确定性的概率关系。\n",
    "从数学上讲，该模型通常被表达为一个概率分布函数或密度函数的集合(Y,P)，其中 Y 是观测集合用来描述可能的观测结果， P 是 Y 对应的概率分布函数集合。\n",
    "若使用概率模型，一般而言需假设存在一个确定的分布P 生成观测数据 Y 。因此通常使用统计推断的办法确定集合 P 中谁是数据产生的原因。\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3. Can you came up with some sceneraies at which we could use Probability Model?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ans:{抛N次硬币出现正面朝上的次数、人类身高的统计分布、财富在人群中的统计分布}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 4. Why do we use probability and what's the difficult points for programming based on parsing and pattern match?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ans:{\n",
    "1) 概率的随机性允许模糊和不确定，概率计算符合大规模的统计结果；互联网大数据的积累为概率统计方法提供了可能。\n",
    "2) 句法分析和模式匹配的困难：自然语言中包含大量歧义，具有模糊性和不确定性；语法规则的开发复杂，并且并不完备。\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 5. What's the Language Model;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ans:{\n",
    "概率语言模型，描述基于大规模语料库，如何计算一条语句出现的概率。\n",
    "典型的N-Gram模型，基于N-1阶马尔可夫链,认为当前词仅与前N-1个词有关,这就解决了维数灾难这个问题。\n",
    "基于条件概率和马尔科夫独立性假设，一条语句出现的概率等于其所有相邻N个词出现的条件概率的连乘积。\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 6. Can you came up with some sceneraies at which we could use Language Model?\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ans:{机器翻译、语音识别、不同风格的语言生成}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 7. What's the 1-gram language model;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ans:{\n",
    "一元语言模型中，一条语句出现的概率定义为其中所有词出现概率的连乘积。\n",
    "基于条件无关假设，即认为每个词都是条件无关的。\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 8. What's the disadvantages and advantages of 1-gram language model;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ans:{\n",
    "缺点：不能判断词之间的上下文关系。\n",
    "优点：计算简单。\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 9. What't the 2-gram models;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ans:{\n",
    "二元语言模型中，一条语句出现的概率定义为其中所有相邻两个词出现概率的连乘积。\n",
    "基于条件概率和马尔科夫独立性假设。\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 编程实践部分"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 1. 设计你自己的句子生成器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如何生成句子是一个很经典的问题，从1940s开始，图灵提出机器智能的时候，就使用的是人类能不能流畅和计算机进行对话。和计算机对话的一个前提是，计算机能够生成语言。\n",
    "\n",
    "计算机如何能生成语言是一个经典但是又很复杂的问题。 我们课程上为大家介绍的是一种基于规则（Rule Based）的生成方法。该方法虽然提出的时间早，但是现在依然在很多地方能够大显身手。值得说明的是，现在很多很实用的算法，都是很久之前提出的，例如，二分查找提出与1940s, Dijstra算法提出于1960s 等等。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在著名的电视剧，电影《西部世界》中，这些机器人们语言生成的方法就是使用的SyntaxTree生成语言的方法。\n",
    "\n",
    "> \n",
    ">\n",
    "\n",
    "![WstWorld](https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1569578233461&di=4adfa7597fb380e7cc0e67190bbd7605&imgtype=0&src=http%3A%2F%2Fs1.sinaimg.cn%2Flarge%2F006eYYfyzy76cmpG3Yb1f)\n",
    "\n",
    "> \n",
    ">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在这一部分，需要各位同学首先定义自己的语言。 大家可以先想一个应用场景，然后在这个场景下，定义语法。例如：\n",
    "\n",
    "在西部世界里，一个”人类“的语言可以定义为：\n",
    "``` \n",
    "human = \"\"\"\n",
    "human = 自己 寻找 活动\n",
    "自己 = 我 | 俺 | 我们 \n",
    "寻找 = 看看 | 找找 | 想找点\n",
    "活动 = 乐子 | 玩的\n",
    "\"\"\"\n",
    "```\n",
    "\n",
    "一个“接待员”的语言可以定义为\n",
    "```\n",
    "host = \"\"\"\n",
    "host = 寒暄 报数 询问 业务相关 结尾 \n",
    "报数 = 我是 数字 号 ,\n",
    "数字 = 单个数字 | 数字 单个数字 \n",
    "单个数字 = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 \n",
    "寒暄 = 称谓 打招呼 | 打招呼\n",
    "称谓 = 人称 ,\n",
    "人称 = 先生 | 女士 | 小朋友\n",
    "打招呼 = 你好 | 您好 \n",
    "询问 = 请问你要 | 您需要\n",
    "业务相关 = 玩玩 具体业务\n",
    "玩玩 = 耍一耍 | 玩一玩\n",
    "具体业务 = 喝酒 | 打牌 | 打猎 | 赌博\n",
    "结尾 = 吗？\"\"\"\n",
    "\n",
    "```\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "请定义你自己的语法: "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "第一个语法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 173,
   "metadata": {},
   "outputs": [],
   "source": [
    "poem = '''\n",
    "sentence => sentence1 sentence1 sentence2 sentence2\n",
    "sentence1 => adj_phrase noun_phrase verb_phrase noun_phrase punctuation\n",
    "sentence2 => noun verb_phrase noun_phrase adj_phrase noun punctuation\n",
    "adj_phrase => num unit\n",
    "noun_phrase => adj noun            \n",
    "verb_phrase => verb\n",
    "num => 一 | 二 | 三 | 两 | 千 | 万 \n",
    "unit => 行 | 只 | 个 | 声 | 里 | 秋 | 冬\n",
    "adj =>  白 | 黄 | 翠 | 青 | 西 | 东 | 北 | 南 \n",
    "noun =>   鹭 |  鹂 | 柳 | 天 | 岭 | 窗 | 雪  | 门 | 吴 | 船\n",
    "verb => 鸣 | 上 | 含 |  泊\n",
    "punctuation => ，| 。| ? | ！\n",
    "'''"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> **评阅点**： 是否提出了和课程上区别较大的语法结构"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "第二个语法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 174,
   "metadata": {},
   "outputs": [],
   "source": [
    "dynast = '''\n",
    "sentence => dy1 dy2 dy3\n",
    "dy1 => verb adverb punctuation\n",
    "dy2 => adj_phrase noun_phrase punctuation\n",
    "dy3 => noun_phrase adverb noun_phrase adj punctuation\n",
    "adj_phrase => num unit\n",
    "noun_phrase => adj noun\n",
    "verb => 念 | 道 | 悲 | 忆\n",
    "adverb => 去去 | 沉沉 | 呜呼 | 呼哉 | 凄凄\n",
    "num => 千 | 万 | 双\n",
    "unit => 行 | 古 | 里\n",
    "adj =>  烟 | 暮 | 楚 | 阔\n",
    "noun =>   波 | 霭 | 天 | 雪 | 船\n",
    "punctuation => ，| 。| ? | ！\n",
    "'''"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> **评阅点**：是否和上一个语法区别比较大"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "TODO: 然后，使用自己之前定义的generate函数，使用此函数生成句子。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 175,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 根据语法描述 grammar_str 生成规则 grammar\n",
    "def create_grammar(grammar_str, split='=>', line_split='\\n'):\n",
    "    grammar = {}\n",
    "    for line in grammar_str.split(line_split):\n",
    "        if not line.strip(): continue\n",
    "        exp, stmt = line.split(split)\n",
    "        grammar[exp.strip()] = [s.split() for s in stmt.split('|')]\n",
    "    return grammar\n",
    "\n",
    "# 根据语法规则生成句子\n",
    "choice = random.choice\n",
    "\n",
    "def generate(gram, target):\n",
    "    if target not in gram: return target # means target is a terminal expression #1\n",
    "    \n",
    "    expaned = [generate(gram, t) for t in choice(gram[target])]  #2\n",
    "    return ''.join([e if e != '/n' else '\\n' for e in expaned if e != 'null']) #3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "TODO: 然后，定义一个函数，generate_n，将generate扩展，使其能够生成n个句子:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 176,
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_n(num):\n",
    "    for i in range(num):\n",
    "        print(generate(gram=create_grammar(poem, split='=>'), target='sentence'))\n",
    "        print(generate(gram=create_grammar(dynast, split='=>'), target='sentence'))\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 177,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "二个南雪含南鹂，千只北门上黄门，天泊黄吴千个鹂。窗上白吴两只鹭！\n",
      "悲去去！双行暮霭！暮天呼哉烟波暮?\n",
      "两只青鹂鸣北鹭，两个西船鸣青窗?柳含黄岭万里门。吴含白雪三里岭。\n",
      "忆呜呼，双古暮波?烟天凄凄暮波烟?\n",
      "三里翠岭鸣南鹂！三行青吴上黄雪?岭鸣北鹭一秋窗，鹭含东鹭两声鹭，\n",
      "忆凄凄?双里烟船，暮船凄凄烟天阔，\n",
      "一个白鹂含翠鹭。三个翠窗含西天?鹂含北窗三秋船。船含南雪两冬雪。\n",
      "道沉沉，万里楚霭。阔雪呼哉烟天暮！\n",
      "二冬南鹂含西吴！两个北窗上白柳?鹭含西雪万个门。柳泊南岭千里窗。\n",
      "悲呜呼！万里烟雪！烟霭凄凄暮天暮！\n"
     ]
    }
   ],
   "source": [
    "generate_n(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> **评阅点**; 运行代码，观察是否能够生成多个句子"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2. 使用新数据源完成语言模型的训练"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "按照我们上文中定义的`prob_2`函数，我们更换一个文本数据源，获得新的Language Model:\n",
    "\n",
    "1. 下载文本数据集（你可以在以下数据集中任选一个，也可以两个都使用）\n",
    "    + 可选数据集1，保险行业问询对话集： https://github.com/Computing-Intelligence/insuranceqa-corpus-zh/raw/release/corpus/pool/train.txt.gz\n",
    "    + 可选数据集2：豆瓣评论数据集：https://github.com/Computing-Intelligence/datasource/raw/master/movie_comments.csv\n",
    "2. 修改代码，获得新的**2-gram**语言模型\n",
    "    + 进行文本清洗，获得所有的纯文本\n",
    "    + 将这些文本进行切词\n",
    "    + 送入之前定义的语言模型中，判断文本的合理程度"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> **评阅点** 1. 是否使用了新的数据集； 2. csv(txt)数据是否正确解析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 156,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\Anaconda3\\envs\\python3\\lib\\site-packages\\IPython\\core\\interactiveshell.py:3058: DtypeWarning: Columns (0,4) have mixed types. Specify dtype option on import or set low_memory=False.\n",
      "  interactivity=interactivity, compiler=compiler, result=result)\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>id</th>\n",
       "      <th>link</th>\n",
       "      <th>name</th>\n",
       "      <th>comment</th>\n",
       "      <th>star</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>https://movie.douban.com/subject/26363254/</td>\n",
       "      <td>战狼2</td>\n",
       "      <td>吴京意淫到了脑残的地步，看了恶心想吐</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2</td>\n",
       "      <td>https://movie.douban.com/subject/26363254/</td>\n",
       "      <td>战狼2</td>\n",
       "      <td>首映礼看的。太恐怖了这个电影，不讲道理的，完全就是吴京在实现他这个小粉红的英雄梦。各种装备轮...</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>3</td>\n",
       "      <td>https://movie.douban.com/subject/26363254/</td>\n",
       "      <td>战狼2</td>\n",
       "      <td>吴京的炒作水平不输冯小刚，但小刚至少不会用主旋律来炒作…吴京让人看了不舒服，为了主旋律而主旋...</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>4</td>\n",
       "      <td>https://movie.douban.com/subject/26363254/</td>\n",
       "      <td>战狼2</td>\n",
       "      <td>凭良心说，好看到不像《战狼1》的续集，完虐《湄公河行动》。</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>5</td>\n",
       "      <td>https://movie.douban.com/subject/26363254/</td>\n",
       "      <td>战狼2</td>\n",
       "      <td>中二得很</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  id                                        link name  \\\n",
       "0  1  https://movie.douban.com/subject/26363254/  战狼2   \n",
       "1  2  https://movie.douban.com/subject/26363254/  战狼2   \n",
       "2  3  https://movie.douban.com/subject/26363254/  战狼2   \n",
       "3  4  https://movie.douban.com/subject/26363254/  战狼2   \n",
       "4  5  https://movie.douban.com/subject/26363254/  战狼2   \n",
       "\n",
       "                                             comment star  \n",
       "0                                 吴京意淫到了脑残的地步，看了恶心想吐    1  \n",
       "1  首映礼看的。太恐怖了这个电影，不讲道理的，完全就是吴京在实现他这个小粉红的英雄梦。各种装备轮...    2  \n",
       "2  吴京的炒作水平不输冯小刚，但小刚至少不会用主旋律来炒作…吴京让人看了不舒服，为了主旋律而主旋...    2  \n",
       "3                      凭良心说，好看到不像《战狼1》的续集，完虐《湄公河行动》。    4  \n",
       "4                                               中二得很    1  "
      ]
     },
     "execution_count": 156,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 读取文件\n",
    "filename = 'movie_comments.csv'\n",
    "content = pd.read_csv(filename, encoding='utf-8')\n",
    "content.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 159,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "261497\n",
      "261497\n"
     ]
    }
   ],
   "source": [
    "# 提取词并写入文件\n",
    "articles = content['comment'].tolist()\n",
    "print(len(articles))\n",
    "\n",
    "def token(string):\n",
    "    # we will learn the regular expression next course.\n",
    "    return re.findall('\\w+', string)\n",
    "\n",
    "articles_clean = [''.join(token(str(a)))for a in articles]\n",
    "print(len(articles_clean))\n",
    "\n",
    "with open('article_movie_comments.txt', 'w', encoding='utf-8') as f:\n",
    "    for a in articles_clean:\n",
    "        f.write(a + '\\n')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 160,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "10000\n",
      "20000\n",
      "30000\n",
      "40000\n",
      "50000\n",
      "60000\n",
      "70000\n",
      "80000\n",
      "90000\n",
      "100000\n"
     ]
    }
   ],
   "source": [
    "# 分词\n",
    "def cut(string): return list(jieba.cut(string))\n",
    "\n",
    "TOKEN = []\n",
    "for i, line in enumerate((open('article_movie_comments.txt','r',encoding='utf-8'))):\n",
    "    if i % 10000 == 0: print(i)\n",
    "    # replace 10000 with a big number when you do your homework. \n",
    "    if i > 100000: break    \n",
    "    TOKEN += cut(line)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 161,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 计算概率\n",
    "words_count = Counter(TOKEN)\n",
    "\n",
    "TOKEN = [str(t) for t in TOKEN]\n",
    "TOKEN_2_GRAM = [''.join(TOKEN[i:i+2]) for i in range(len(TOKEN[:-2]))]\n",
    "words_count_2 = Counter(TOKEN_2_GRAM)\n",
    "\n",
    "def prob_1(word):\n",
    "    return words_count[word] / len(TOKEN)\n",
    "# count(wk)/(number of words)\n",
    "\n",
    "def prob_2(word1, word2):  # p(w1,w2) = count(w1,2)/count(w1)\n",
    "    if word1 + word2 in words_count_2: return words_count_2[word1+word2] / words_count[word1]\n",
    "    else:\n",
    "        return 1 / len(TOKEN_2_GRAM)\n",
    "    \n",
    "#  (w1 w2), (w3,w4) (w4,w5)  2-gram\n",
    "# (w1,w3)  1/3\n",
    "\n",
    "def get_probablity(sentence):\n",
    "    words = cut(sentence)\n",
    "    \n",
    "    sentence_pro = 1\n",
    "    \n",
    "    for i, word in enumerate(words[:-1]):\n",
    "        next_ = words[i+1]\n",
    "        \n",
    "        probability = prob_2(word, next_)  # p(w1|w2)\n",
    "        \n",
    "        sentence_pro *= probability  # p(s) = p(w_1)p(w2|w1)*p(w3|w2)..p(wn|wn-1) \n",
    "    \n",
    "    return sentence_pro"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 162,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "9.70386170001317e-34"
      ]
     },
     "execution_count": 162,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 测试句子\n",
    "get_probablity('小明今天抽奖抽到一台苹果手机')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 163,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.8457615165129006e-38"
      ]
     },
     "execution_count": 163,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "get_probablity('小明今天抽奖抽到一架波音飞机')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 164,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.3585880599037004e-19"
      ]
     },
     "execution_count": 164,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "get_probablity('洋葱奶昔来一杯')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 165,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2.6427648931784153e-13"
      ]
     },
     "execution_count": 165,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "get_probablity('养乐多绿来一杯')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 166,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sentence: 这个小小的篮球坐在一个好看的小小的篮球 with Prb: 9.148833685560679e-36\n",
      "sentence: 这个桌子看着一个桌子 with Prb: 1.4721866189997572e-19\n",
      "sentence: 一个蓝色的小猫听着一个篮球 with Prb: 2.7724091138702786e-25\n",
      "sentence: 一个小小的篮球看着这个小小的好看的小猫 with Prb: 2.2405658722232148e-38\n",
      "sentence: 一个篮球看见一个女人 with Prb: 3.659519732969293e-15\n",
      "sentence: 一个好看的好看的小小的小小的好看的小小的女人听着一个好看的小小的篮球 with Prb: 6.41836229751587e-67\n",
      "sentence: 这个桌子看见一个蓝色的女人 with Prb: 1.6980659859160636e-25\n",
      "sentence: 一个蓝色的桌子坐在一个小猫 with Prb: 1.6379470639344089e-28\n",
      "sentence: 这个女人看见这个小小的小小的蓝色的小猫 with Prb: 3.230240515191667e-33\n",
      "sentence: 这个好看的篮球看着这个篮球 with Prb: 1.8124899258809507e-27\n"
     ]
    }
   ],
   "source": [
    "for sen in [generate(gram=example_grammar, target='sentence') for i in range(10)]:\n",
    "    print('sentence: {} with Prb: {}'.format(sen, get_probablity(sen)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 167,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "今天晚上请你吃大餐，我们一起吃日料 is more possible\n",
      "---- 今天晚上请你吃大餐，我们一起吃日料 with probility 2.0720365197865112e-42\n",
      "---- 明天晚上请你吃大餐，我们一起吃苹果 with probility 4.510828857674769e-43\n",
      "真是一只好看的小猫 is more possible\n",
      "---- 真事一只好看的小猫 with probility 2.5332326717830002e-21\n",
      "---- 真是一只好看的小猫 with probility 8.199229747670979e-19\n",
      "今晚我去吃火锅 is more possible\n",
      "---- 今晚我去吃火锅 with probility 8.562263341759753e-11\n",
      "---- 今晚火锅去吃我 with probility 3.881253468807565e-18\n",
      "养乐多绿来一杯 is more possible\n",
      "---- 洋葱奶昔来一杯 with probility 1.3585880599037004e-19\n",
      "---- 养乐多绿来一杯 with probility 2.6427648931784153e-13\n"
     ]
    }
   ],
   "source": [
    "need_compared = [\n",
    "    \"今天晚上请你吃大餐，我们一起吃日料 明天晚上请你吃大餐，我们一起吃苹果\",\n",
    "    \"真事一只好看的小猫 真是一只好看的小猫\",\n",
    "    \"今晚我去吃火锅 今晚火锅去吃我\",\n",
    "    \"洋葱奶昔来一杯 养乐多绿来一杯\"\n",
    "]\n",
    "\n",
    "for s in need_compared:\n",
    "    s1, s2 = s.split()\n",
    "    p1, p2 = get_probablity(s1), get_probablity(s2)\n",
    "    \n",
    "    better = s1 if p1 > p2 else s2\n",
    "    \n",
    "    print('{} is more possible'.format(better))\n",
    "    print('-'*4 + ' {} with probility {}'.format(s1, p1))\n",
    "    print('-'*4 + ' {} with probility {}'.format(s2, p2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3. 获得最优质的的语言"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当我们能够生成随机的语言并且能判断之后，我们就可以生成更加合理的语言了。请定义 generate_best 函数，该函数输入一个语法 + 语言模型，能够生成**n**个句子，并能选择一个最合理的句子: \n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "提示，要实现这个函数，你需要Python的sorted函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 3, 5]"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sorted([1, 3, 5, 2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个函数接受一个参数key，这个参数接受一个函数作为输入，例如"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(1, 4), (2, 5), (4, 4), (5, 0)]"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sorted([(2, 5), (1, 4), (5, 0), (4, 4)], key=lambda x: x[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "能够让list按照第0个元素进行排序."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(5, 0), (1, 4), (4, 4), (2, 5)]"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sorted([(2, 5), (1, 4), (5, 0), (4, 4)], key=lambda x: x[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "能够让list按照第1个元素进行排序."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(2, 5), (1, 4), (4, 4), (5, 0)]"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sorted([(2, 5), (1, 4), (5, 0), (4, 4)], key=lambda x: x[1], reverse=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "能够让list按照第1个元素进行排序, 但是是递减的顺序。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 181,
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_best(grammar_string, language_model, num): # you code here\n",
    "    sentences = []\n",
    "    for i in range(num):\n",
    "        # 生成句子\n",
    "        sentence = generate(gram=create_grammar(grammar_string, split='=>'), target='sentence')\n",
    "        # 计算概率\n",
    "        probability = language_model(sentence)\n",
    "        sentences.append((sentence, probability))\n",
    "    # 按概率降序排序\n",
    "    sorted(sentences, key=lambda x: x[1], reverse=True)\n",
    "    return sentences[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 190,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('二只翠门鸣西鹭，万秋青吴鸣黄雪，窗上东鹂千声雪，天上青鹭一里天！', 2.3794042425808864e-101)"
      ]
     },
     "execution_count": 190,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "generate_best(poem, get_probablity, 20)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "好了，现在我们实现了自己的第一个AI模型，这个模型能够生成比较接近于人类的语言。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> **评阅点**： 是否使用 lambda 语法进行排序"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q: 这个模型有什么问题？ 你准备如何提升？ "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ans:{\n",
    "1)生成句子的语法规则太简单，规则中的词太少；\n",
    "2)生成的句子是四言古诗，概率语言模型使用的语料库应该是唐诗三百首之类。\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**评阅点**: 是否提出了比较实际的问题，例如OOV问题，例如数据量，例如变成 3-gram问题。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 以下内容为可选部分，对于绝大多数同学，能完成以上的项目已经很优秀了，下边的内容如果你还有精力可以试试，但不是必须的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 4. (Optional) 完成基于Pattern Match的语句问答\n",
    "> 另外一份作业文件里有个optional，有兴趣的同学可以挑战一下"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "各位同学，我们已经完成了自己的第一个AI模型，大家对人工智能可能已经有了一些感觉，人工智能的核心就是，我们如何设计一个模型、程序，在外部的输入变化的时候，我们的程序不变，依然能够解决问题。人工智能是一个很大的领域，目前大家所熟知的深度学习只是其中一小部分，之后也肯定会有更多的方法提出来，但是大家知道人工智能的目标，就知道了之后进步的方向。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "然后，希望大家对AI不要有恐惧感，这个并不难，大家加油！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1561828422005&di=48d19c16afb6acc9180183a6116088ac&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201807%2F28%2F20180728150843_BECNF.thumb.224_0.jpeg)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
